#pragma once

#include "GrvConstraint.h"
#include "GrvContactManifold.h"


Meson_Gravitas_Constraint_BEGIN

//------------------------------------------------------------------------------------------
/// Returns a pointer to the memory manager for Gravitas contact constraints.
/// \returns a pointer to the memory manager for Gravitas contact constraints.
//------------------------------------------------------------------------------------------
Meson::Common::Memory::MemoryManager* GetContactConstraintMemoryManager(void);

//------------------------------------------------------------------------------------------
/// \class ContactConstraint
/// An instantaneous collision and contact constraint implementation. Instances of this
/// constraint are generated by the simulator following the collision detection phase.
/// Depending on the contact manifold geometry, the constraint may consist of one or more
/// constraint discrepancies where the interpenetration and required post-collision velocity
/// are represented by the positional discrepancy points and the required relative velocity,
/// respectively.
//------------------------------------------------------------------------------------------
class GRAVITAS_API ContactConstraint
	: public IConstraint
{
private: // private variables
	static const Meson::Common::Text::String s_strType;

public: // public variables
	//------------------------------------------------------------------------------------------
	/// First body affected by the contact constraint.
	//------------------------------------------------------------------------------------------
	Meson::Gravitas::Body::BodyPtr Body1;

	//------------------------------------------------------------------------------------------
	/// Second body affected by the contact constraint.
	//------------------------------------------------------------------------------------------
	Meson::Gravitas::Body::BodyPtr Body2;

	//------------------------------------------------------------------------------------------
	/// List of contact constraint discrepancies.
	//------------------------------------------------------------------------------------------
	ConstraintDiscrepancyArrayList ConstraintDiscrepancies;

public: // public methods
	//------------------------------------------------------------------------------------------
	/// Constructs a contact constraint.
	//------------------------------------------------------------------------------------------
	ContactConstraint(void);

	//------------------------------------------------------------------------------------------
	/// Constructs a contact constraint from the given contact manifold.
	/// \param p_contactManifold Contact manifold structure used to build contact constraint.
	//------------------------------------------------------------------------------------------
	ContactConstraint(const Meson::Gravitas::Collision::ContactManifold& p_contactManifold);

	//------------------------------------------------------------------------------------------
	/// Destroys the contact constraint.
	//------------------------------------------------------------------------------------------
	~ContactConstraint(void);

	//------------------------------------------------------------------------------------------
	/// Allocates memory for the object prior to construction.
	/// \param p_unSize Size of the required memory buffer in bytes.
	/// \returns a pointer to the allocated buffer.
	//------------------------------------------------------------------------------------------
	void* operator new(size_t p_unSize);

	//------------------------------------------------------------------------------------------
	/// Deallocates the object's memory following destruction.
	/// \param p_pObject Pointer to the memory buffer to deallocate.
	/// \param p_unSize Size of the memory buffer in bytes.
	//------------------------------------------------------------------------------------------
	void operator delete(void* p_pObject, size_t p_unSize);

	// IConstraint interface
	const Meson::Common::Text::String& GetType(void) const;

	Meson::Gravitas::Body::BodyPtr GetBody1(void);
	void SetBody1(Meson::Gravitas::Body::BodyPtr p_pBody1);

	Meson::Gravitas::Body::BodyPtr GetBody2(void);
	void SetBody2(Meson::Gravitas::Body::BodyPtr p_pBody2);

	void Bind(void);
	void Unbind(void);

	bool IsInstantaneous(void) const;

	bool IsBroken(void) const;
	void SetBroken(bool p_bBroken);
	Real GetBreakingThreshold(void) const;
	void SetBreakingThreshold(Real p_rValue);

	bool CanRecomputeDiscrepancies(void);
	void ComputeDiscrepancies(void);
	const ConstraintDiscrepancyList& GetDiscrepancies(void);
};

Meson_Gravitas_Constraint_END
